//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
//==
//==
//==
//==================================================================

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "m5d_model.h"
#include "m5d_scene.h"
//==================================================================
using namespace M5D;

//==================================================================
Model::Model( Type type, class Scene *scenep, const char *namep ) :
	_mod_type(		type ),
	_mod_visible(	true ),
	_mod_nextp(		NULL ),
	_mod_childp(	NULL ),
	_mod_parentp(	NULL ),
	_mod_scenep(	scenep ),
	_userdatap(		NULL ),
	_mod_flags(		0 )
{
	_mod_name[0]	= 0;

	_mod_local_m.Identity();
	_mod_global_m.Identity();

	if ( namep )
		SetName( namep );
}

//==================================================================
Model::~Model()
{
	UnlinkFromTree();
	_mod_scenep->unlinkModel( this );
}

//==================================================================
void Model::GetBranchBBox( Vector3 &bbox_min, Vector3 &bbox_max )
{
	bbox_min.SetMaxValue();
	bbox_max.SetMinValue();

	getBranchBBox_sub( bbox_min, bbox_max );
}

//==================================================================
void Model::getBranchBBox_sub( Vector3 &bbox_min, Vector3 &bbox_max )
{
	const Vector3	*loc_bbox_minp = GetBBoxMinPtr();
	const Vector3	*loc_bbox_maxp = GetBBoxMaxPtr();

	if ( loc_bbox_minp )
	{
		bbox_min.SetMin( _mod_global_m * *loc_bbox_minp );
		bbox_max.SetMax( _mod_global_m * *loc_bbox_maxp );
	}

	if ( _mod_childp )
	{
		_mod_childp->getBranchBBox_sub( bbox_min, bbox_max );

		for (Model *nextp = _mod_childp->_mod_nextp; nextp; nextp = nextp->_mod_nextp)
			nextp->getBranchBBox_sub( bbox_min, bbox_max );
	}
}

//==================================================================
void Model::SetBranchVisibility( bool onoff )
{
	_mod_visible = onoff;
	if ( _mod_childp )
	{
		_mod_childp->SetBranchVisibility( onoff );

		for (Model *nextp = _mod_childp->_mod_nextp; nextp; nextp = nextp->_mod_nextp)
			nextp->SetBranchVisibility( onoff );
	}
}

//==================================================================
Model *Model::FindByName( const char *namep )
{
	if ( _stricmp( _mod_name, namep ) == 0 )
		return this;

	Model	*foundp;

	if ( _mod_childp )
		if ( foundp = _mod_childp->FindByName( namep ) )
			return foundp;

	if ( _mod_nextp )
		if ( foundp = _mod_nextp->FindByName( namep ) )
			return foundp;

	return NULL;
}

//==================================================================
void Model::UnlinkFromTree()
{
	Model	*childp = _mod_childp;
	for (; childp; childp = childp->_mod_nextp)
	{
		PASSERT ( childp->_mod_parentp == this );
		childp->_mod_parentp = _mod_parentp;
	}
	if ( _mod_parentp )
	{
		if ( _mod_parentp->_mod_childp == this )
		{
			if ( _mod_nextp )
				_mod_parentp->_mod_childp = _mod_nextp;
			else
				_mod_parentp->_mod_childp = _mod_childp;
		}

		Model	*siblingp = _mod_parentp->_mod_childp;
		while ( siblingp )
		{
			if ( siblingp->_mod_nextp == this )
			{
				siblingp->_mod_nextp = _mod_nextp;
				break;
			}

			siblingp = siblingp->_mod_nextp;
		}
	}
}

//==================================================================
void Model::SetName( const char *namep )
{
	strcpy_s( _mod_name, namep );
}

//==================================================================
void Model::UpdateGlobalTransform()
{
	if ( _mod_parentp )
		_mod_global_m = _mod_parentp->_mod_global_m * _mod_local_m;
	else
		_mod_global_m = _mod_local_m;

	if ( _mod_childp )
	{
		_mod_childp->UpdateGlobalTransform();

		for (Model *nextp = _mod_childp->_mod_nextp; nextp; nextp = nextp->_mod_nextp)
			nextp->UpdateGlobalTransform();
	}
}

//==================================================================
void Model::AddChild( Model *new_nodep )
{
	new_nodep->_mod_parentp = this;

	if ( _mod_childp )	// has children
	{
		new_nodep->_mod_nextp = _mod_childp;
		_mod_childp = new_nodep;
	}
	else
	{
		_mod_childp = new_nodep;
	}
}

//==================================================================
///
//==================================================================
void Model::CopyParams::SetDefault()
{
	_copy_geometry = false;
	_copy_geometry_idx_dlist = false;
	_copy_geometry_vtx_dlist = false;
	_copy_geometry_verts = false;
	_copy_geometry_trigs = false;
	_copy_geometry_create_vtx_dlist = false;
	for (int i=0; i < VType::N; ++i)
		_copy_geometry_create_vtx_dlist_forcetypes[i] = false;
}
